package com.bifrost.service.impl;

import com.bifrost.common.base.ServerResponse;
import com.bifrost.constant.Constant;
import com.bifrost.entity.Permission;
import com.bifrost.entity.Role;
import com.bifrost.entity.User;
import com.bifrost.model.param.PermissionParam;
import com.bifrost.model.vo.PermissionVO;
import com.bifrost.repository.AdminUserRepository;
import com.bifrost.repository.PermissionRepository;
import com.bifrost.repository.RoleRepository;
import com.bifrost.service.PermissionService;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * Author by yanxiaobo
 * Date on 2018/4/10$.
 */
@Service("permissionService")
@Transactional
public class PermissionServiceImpl implements PermissionService {
    public static final String PREFIX = "customPerms[";
    //public static final String PREFIX = "perms[";
    public static final String SUFFIX = "]";
    public static final String SEPARATOR = ",";

    @Autowired
    PermissionRepository permissionRepository;
    @Autowired
    AdminUserRepository adminUserRepository;
    @Autowired
    RoleRepository roleRepository;


    @Override
    public ServerResponse list() {
        Sort sort = new Sort("type", "order");
        List<Permission> permissionList = permissionRepository.findAll(sort);
        Set<PermissionVO> voSet = assemblePermissionVO(permissionList);
        return ServerResponse.createBySuccess(voSet);
    }

    /**
     * 初始化权限数据
     *
     * @return
     */
    @Override
    public Map<String, String> buildFilterChainDefinitionMap() {
        List<Permission> permissionList = permissionRepository.findAll();
        Map<String, String> map = new LinkedHashMap<>();
        if (CollectionUtils.isNotEmpty(permissionList)) {
            for (Permission permission : permissionList) {
                String argus = permission.getUrl();
                if (StringUtils.isNotEmpty(argus)) {//没有url的不纳入权限管理
                    String[] urlArr = argus.split(SEPARATOR);
                    for (String url : urlArr)
                        map.put(url, PREFIX + permission.getIdentifier() + SUFFIX);
                }
            }
        }
        return map;
    }

    @Override
    public ServerResponse getUserPermissions(Integer userId) {
        if (null == userId)
            return ServerResponse.createByErrorMsg("参数错误");
        User user = adminUserRepository.findOne(userId.longValue());
        if (null == user)
            return ServerResponse.createBySuccessMsg("不存在该用户");
        Set<String> permissions = new HashSet<>();//采用set，用于去重。存储用户的所有权限
        Set<PermissionVO> permissionVOSet = new HashSet<>();//用于存储用于能够看见的菜单
        Set<Role> roleSet = user.getRoles();
        if (CollectionUtils.isNotEmpty(roleSet)) {
            for (Role role : roleSet) {
                Set<Permission> permissionSet = role.getPermissions();
                if (CollectionUtils.isNotEmpty(permissionSet)) {
                    for (Permission permission : permissionSet) {
                        if (Constant.Permission.PERMISSION_TYPE_MENU == permission.getType()) {
                            PermissionVO permissionVO = PermissionVO.adapter(permission);
                            permissionVOSet.add(permissionVO);
                        } else {
                            permissions.add(permission.getPermissionName());
                        }
                    }
                }
            }
        }
        Map<String, Set> map = new HashMap<>();
        map.put("permissions", permissions);
        map.put("menuList", permissionVOSet);
        return ServerResponse.createBySuccess(map);
    }

    @Override
    public ServerResponse add(PermissionParam param) {
        Permission permission = Permission.builder()
                .permissionName(param.getName())
                .menuURL(param.getUrl())
                .order(param.getOrderNum())
                .type(param.getType())
                .url(param.getPerms())
                .permissionDescription(param.getDescription())
                .icon(param.getIcon())
                .identifier(StringUtils.isBlank(param.getIdentifier()) ? null : param.getIdentifier())//identity为空字符串的话，设置为null
                .build();
        permission.setCreatedTimestamp(new Date());
        //校验名称是否重复
        ServerResponse response = checkNameNotExist(param.getParentId(), param.getMenuId(), param.getName());
        if (!response.isSuccess())
            return response;
        //校验identifier是否重复
        if(StringUtils.isNotEmpty(param.getIdentifier())) {
            response = checkIdentifierNotExist(param.getIdentifier(),null,false);
            if(!response.isSuccess())
                return response;
        }
        if (null != param.getParentId()) {
            //校验parent是否存在
            response = checkPermissionNotExist(param.getParentId());
            if (!response.isSuccess())
                return response;
            permission.setParent((Permission) response.getData());
            //校验parent是否合法：目录的父级只能是目录，菜单的父级必须是目录，按钮的父级必须是菜单
            response = validateType(permission.getParent().getId(), permission.getType());
            if (!response.isSuccess())
                return response;
        }
        //校验order是否合法：相同父级下已有order：1、2、3那么合法的order为1,2,3,4
        response = validateOrder(permission.getOrder(), param.getParentId(),false);
        if (!response.isSuccess())
            return response;
        //维护该父级下的权限的order，使当前新增的权限能够放在一个正确的位置
        response = fixBeforeAddOrDelete(permission.getOrder(), param.getParentId(),true);
        if (!response.isSuccess())
            return response;
        Permission retrive = permissionRepository.save(permission);
        if (null == retrive)
            return ServerResponse.createByErrorMsg("新增失败");
        return ServerResponse.createBySuccess("新增成功");
    }

    @Override
    public ServerResponse update(PermissionParam param, User currentUser) {
        Permission permission = Permission.builder()
                .id(param.getMenuId())
                .permissionName(param.getName())
                .menuURL(param.getUrl())
                .order(param.getOrderNum())
                .type(param.getType())
                .url(param.getPerms())
                .permissionDescription(param.getDescription())
                .icon(param.getIcon())
                .identifier(StringUtils.isBlank(param.getIdentifier()) ? null : param.getIdentifier())
                .build();

        permission.setUpdatedTimestamp(new Date());
        permission.setUpdatedBy(currentUser.getAdminName());

        //校验要更新的权限是否存在
        ServerResponse response = checkPermissionNotExist(permission.getId());
        if (!response.isSuccess())
            return response;
        //校验identifier是否重复
        if(StringUtils.isNotEmpty(param.getIdentifier())) {
            response = checkIdentifierNotExist(param.getIdentifier(),param.getMenuId(),true);
            if(!response.isSuccess())
                return response;
        }
        //校验名称是否重复
        response = checkNameNotExist(param.getParentId(), param.getMenuId(), param.getName());
        if (!response.isSuccess())
            return response;
        if (null != param.getParentId()) {
            //校验parent是否存在
            response = checkPermissionNotExist(param.getParentId());
            if (!response.isSuccess())
                return response;
            permission.setParent((Permission) response.getData());
            //校验parent是否合法：目录的父级只能是目录，菜单的父级必须是目录，按钮的父级必须是菜单
            response = validateType(permission.getParent().getId(), permission.getType());
            if (!response.isSuccess())
                return response;
        }
        //校验order是否合法：相同父级下已有order：1、2、3那么合法的order为1,2,3,4
        response = validateOrder(permission.getOrder(), param.getParentId(), true);
        if (!response.isSuccess())
            return response;
        //维护该父级下的权限的order，使当前新增的权限能够放在一个正确的位置
        response = fixBeforeUpdate(permission.getOrder(), param.getParentId(), param.getMenuId());
        if (!response.isSuccess())
            return response;
        Permission retrive = permissionRepository.save(permission);
        if (null == retrive)
            return ServerResponse.createByErrorMsg("修改失败");
        return ServerResponse.createBySuccess("修改成功");
    }

    private ServerResponse checkIdentifierNotExist(String identifier, Integer menuId,boolean isUpdateOperation) {
        Permission conflict = permissionRepository.findByIdentifier(identifier);
        if(null == conflict)
            return ServerResponse.createBySuccess();
        if(isUpdateOperation) {
            if(conflict.getId() == menuId)
                return ServerResponse.createBySuccess();
        }
        return ServerResponse.createByErrorMsg("授权标识已经存在");
    }

    @Override
    public ServerResponse delete(Integer menuId) {
        //校验要删除的权限是否存在
        ServerResponse response = checkPermissionNotExist(menuId);
        if (!response.isSuccess())
            return response;
        response = recursivelyDelete(menuId);
        return response;
    }

    private ServerResponse recursivelyDelete(Integer menuId) {
        Permission permission = permissionRepository.findOne(menuId);
        Set<Permission> children = permission.getChildren();
        if (CollectionUtils.isNotEmpty(children)) {
            for (Permission child : children) {
                recursivelyDelete(child.getId());
            }
        }
        Permission target = permissionRepository.findOne(menuId);
        ServerResponse  response = fixBeforeAddOrDelete(target.getOrder(),target.getParent()==null ? null : target.getParent().getId(),false);
        if(!response.isSuccess())
            return response;

        //消除外键依赖
        Set<Role> roles = target.getRoles();
        if(CollectionUtils.isNotEmpty(roles)) {
            for(Role role : roles) {
                role.getPermissions().remove(target);
            }
            roleRepository.save(roles);
        }

        permissionRepository.delete(menuId);
        return ServerResponse.createBySuccessMsg("删除成功");
    }


    private ServerResponse checkNameNotExist(Integer parentId, Integer id, String name) {
        Permission duplicate = null;
        Permission parent = null;
        if (null != parentId)
            parent = permissionRepository.findOne(parentId);
        duplicate = permissionRepository.findByParentAndPermissionName(parent, name);
        if (null == duplicate)
            return ServerResponse.createBySuccess();
        if (id != null) {//更新
            if (duplicate.getId() == id)
                return ServerResponse.createBySuccess();
        }
        return ServerResponse.createByErrorMsg("名称已经被占用");
    }

    private ServerResponse fixBeforeUpdate(int order, Integer parentId, Integer id) {
        Permission before = permissionRepository.findOne(id);
        int oldOrder = before.getOrder();
        if (order == oldOrder)
            return ServerResponse.createBySuccess();
        List<Permission> brother = getBrother(parentId);
        Map<Integer, Permission> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(brother)) {
            for (Permission p : brother) {
                map.put(p.getOrder(), p);
            }
        }
        Permission conflict = map.get(order);//将发生冲突的权限的order更改为oldOrder
        conflict.setOrder(oldOrder);
        Permission retrive = permissionRepository.save(conflict);
        if (null == retrive)
            return ServerResponse.createByErrorMsg("系统错误");
        return ServerResponse.createBySuccess();
    }

    private ServerResponse fixBeforeAddOrDelete(int order, Integer parentId,boolean isAddOperation) {
        List<Permission> brother = getBrother(parentId);
        Map<Integer, Permission> map = new HashMap<>();
        List<Integer> existOrders = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(brother)) {
            for (Permission p : brother) {
                map.put(p.getOrder(), p);
                existOrders.add(p.getOrder());
            }
        }
        Collections.sort(existOrders);
        Permission conflict = map.get(order);
        List<Permission> permissionList = Lists.newArrayList();
        if (null != conflict) {//如果插入的order已经存在
            //如果是增加将发生冲突以及以后的o权限order + 1,如果是删除将order+1及以后的order - 1
            for (int i = (isAddOperation ? order : order+1); i <= existOrders.get(existOrders.size() - 1); i++) {
                Permission permission = map.get(i);
                permission.setOrder(permission.getOrder() + (isAddOperation ? 1 : -1));//增加的话+1，删除的话-1
                permissionList.add(permission);//存储要更改order字段的权限
            }
        }
        List<Permission> retrives = permissionRepository.save(permissionList);
        if (null == retrives)
            return ServerResponse.createByErrorMsg("系统发生错误");
        return ServerResponse.createBySuccess();
    }

    private List<Permission> getBrother(Integer parentId) {
        List<Permission> brother = Lists.newArrayList();
        if (null == parentId)//如果父级为空，那么新增的权限为目录
            brother = permissionRepository.findByParent(null);
        else {
            Permission parent = permissionRepository.findOne(parentId);
            Set<Permission> children = parent.getChildren();
            if (CollectionUtils.isNotEmpty(children)) {
                for (Permission child : children) {
                    brother.add(child);
                }
            }
        }
        return brother;
    }

    /**
     * 校验parent是否合法：菜单的父级必须是目录，按钮的父级必须是菜单
     *
     * @param id
     * @param type
     * @return
     */
    private ServerResponse validateType(Integer id, int type) {
        Permission permission = permissionRepository.findOne(id);
        if (null == permission)
            return ServerResponse.createByErrorMsg("不存在该父级");
        boolean isValid = false;
        if (Constant.Permission.PERMISSION_TYPE_MENU == type)
            isValid = permission.getType() == Constant.Permission.PERMISSION_TYPE_INDEX;
        else if (Constant.Permission.PERMISSION_TYPE_BUTTON == type)
            isValid = permission.getType() == Constant.Permission.PERMISSION_TYPE_MENU;
        if (isValid)
            return ServerResponse.createBySuccess();
        return ServerResponse.createByErrorMsg("权限的父级权限不合法");
    }

    /**
     * 校验order是否合法：相同父级下已有order：1、2、3那么合法的order为1,2,3,4
     *
     * @param order
     * @param parentId
     * @return
     */
    private ServerResponse validateOrder(int order, Integer parentId, boolean isUpdateOperation) {
        List<Permission> brother = getBrother(parentId);
        List<Integer> existOrders = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(brother)) {
            for (Permission p : brother) {
                existOrders.add(p.getOrder());
            }
        }
        Collections.sort(existOrders);//对已经存在的序列进行排序
        if (CollectionUtils.isNotEmpty(existOrders)) {
            int maxOrder = existOrders.get(existOrders.size() - 1) + 1;
            if (existOrders.contains(order) || (!isUpdateOperation)&&maxOrder == order) {
                return ServerResponse.createBySuccess();
            }
            return ServerResponse.createByErrorMsg("排序号不合法");
        } else {
            if (1 == order)
                return ServerResponse.createBySuccess();
            return ServerResponse.createByErrorMsg("排序号不合法");
        }
    }

    private ServerResponse checkPermissionNotExist(Integer id) {
        Permission permission = permissionRepository.findOne(id);
        if (null == permission)
            return ServerResponse.createByErrorMsg("不存在权限");
        return ServerResponse.createBySuccess(permission);
    }


    private Set<PermissionVO> assemblePermissionVO(List<Permission> permissionList) {
        Set<PermissionVO> set = new HashSet<>();
        Iterator<Permission> iterator = permissionList.iterator();
        while (iterator.hasNext()) {
            Permission permission = iterator.next();
            PermissionVO permissionVO = PermissionVO.adapter(permission);
            set.add(permissionVO);
        }
        return set;
    }
}
